package com.xiaohei.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaohei.auth.mapper.SysMenuMapper;
import com.xiaohei.auth.mapper.SysRoleMenuMapper;
import com.xiaohei.auth.service.SysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaohei.auth.service.SysRoleMenuService;
import com.xiaohei.auth.util.MenuHelper;
import com.xiaohei.common.config.exception.XiaoheiException;
import com.xiaohei.model.system.SysMenu;
import com.xiaohei.model.system.SysRoleMenu;
import com.xiaohei.vo.system.AssginMenuVo;
import com.xiaohei.vo.system.MetaVo;
import com.xiaohei.vo.system.RouterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author xiaohei
 * @since 2024-04-25
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysRoleMenuService sysRoleMenuService;

    @Override
    public List<SysMenu> findNodes() {
        //1.查询你所有菜单数据
        List<SysMenu> sysMenuList = this.list();
        if (CollectionUtils.isEmpty(sysMenuList)) {
            return null;
        }
        //2.构建树形结构
        List<SysMenu> resultList = MenuHelper.buildTreeList(sysMenuList);

        return resultList;
    }

    /**
     * 删除菜单
     *
     * @param id
     */
    @Override
    public void removeMenuById(Long id) {

        //1.判断当前菜单是否有子菜单，如果有子菜单则不能删除
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getParentId, id);
        Integer count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            //说明有子菜单
            throw new XiaoheiException(201, "当前菜单有子菜单不能删除");
        }

        //2.删除菜单
        baseMapper.deleteById(id);

    }

    /**
     * 查询所有菜单和角色分配的菜单
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysMenu> findMenuByRoleId(Long roleId) {
        //1.查询所有菜单 status = 1的
        LambdaQueryWrapper<SysMenu> wrapperSysMenu = new LambdaQueryWrapper<>();
        wrapperSysMenu.eq(SysMenu::getStatus, 1);
        List<SysMenu> allSysMenuList = sysMenuService.getBaseMapper().selectList(wrapperSysMenu);

        //2. 根据roleID进行查询（角色菜单表）对应的所有menuID
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuService
                .list(new LambdaQueryWrapper<SysRoleMenu>()
                        .eq(SysRoleMenu::getRoleId, roleId));

        //3. 根据获取菜单id，获取对应菜单对象
        List<Long> menuIdList = sysRoleMenuList.stream().map(c -> c.getMenuId()).collect(Collectors.toList());

        //3.1  拿着菜单id和所有菜单集合里面id进行比较  如果相同则封装
        allSysMenuList.stream().forEach(item -> {
            if (menuIdList.contains(item.getId())) {
                item.setSelect(true);
            } else {
                item.setSelect(false);
            }
        });

        //4. 返回规定格式菜单列表   树形
        List<SysMenu> sysMenuList = MenuHelper.buildTreeList(allSysMenuList);

        return sysMenuList;
    }

    @Override
    public void doAssign(AssginMenuVo assginMenuVo) {
        //1. 根据角色id删除rolemenu里的数据  分配数据
        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRoleMenu::getRoleId, assginMenuVo.getRoleId());
        sysRoleMenuService.remove(wrapper);

        //2. 从参数里边获取新分配的菜单id列表  进行遍历  把每个id添加到菜单角色关系表里
        List<Long> menuIdList = assginMenuVo.getMenuIdList();

        for (Long menuId : menuIdList) {
            if (StringUtils.isEmpty(menuId)) {
                continue;
            }
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setMenuId(menuId);
            sysRoleMenu.setRoleId(assginMenuVo.getRoleId());
            sysRoleMenuService.save(sysRoleMenu);
        }
    }

    /**
     * 查询用户可以操作的菜单列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<RouterVo> findUserMenuListByUserId(Long userId) {
        List<SysMenu> sysMenuList = null;
        //1. 判断当前用户是否是管理员   userId = 1
        if (userId.equals(1L)) {
            //1.1 如果是则可以获取所有菜单列表
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysMenu::getStatus, 1);
            queryWrapper.orderByAsc(SysMenu::getSortValue);
            sysMenuList = baseMapper.selectList(queryWrapper);
        } else {
            //1.2 根据userId查询角色信息(角色id  用户角色表)
            //多表联查：用户角色关系表、角色菜单关系表、菜单表
            sysMenuList = baseMapper.findMenuListByUserId(userId);

        }

        //2. 把查询出来的数据列表构建成框架要求的路由结构  返回
        List<SysMenu> sysMenuTreeList = MenuHelper.buildTreeList(sysMenuList);
        //构建成框架要求结构
        List<RouterVo> routerList = this.buildRouter(sysMenuTreeList);
        return routerList;
        //自己试试
        //2. 根据角色查询对应权限(角色菜单表)
        //3. 最后封装成框架要求的结构  返回
//        return null;
    }

    //构建成框架要求的结构
    private List<RouterVo> buildRouter(List<SysMenu> menus) {
        //创建List集合存储最终的数据
        List<RouterVo> routers = new ArrayList<>();
        //menus遍历
        for (SysMenu menu : menus) {
            RouterVo router = new RouterVo();
            router.setHidden(false);
            router.setAlwaysShow(false);
            router.setPath(getRouterPath(menu));
            router.setComponent(menu.getComponent());
            router.setMeta(new MetaVo(menu.getName(), menu.getIcon()));
            //封装下一层数据
            List<SysMenu> children = menu.getChildren();
            //判断是否有隐藏路由
            if (menu.getType().intValue() == 1) {
                //加载下面的隐藏路由
                List<SysMenu> hiddenMenuList = children.stream()
                        .filter(item -> !StringUtils.isEmpty(item.getComponent()))
                        .collect(Collectors.toList());
                for (SysMenu hiddenMenu : hiddenMenuList) {
                    RouterVo hiddenRouter = new RouterVo();
                    //true  是一个隐藏路由
                    hiddenRouter.setHidden(true);
                    hiddenRouter.setAlwaysShow(false);
                    hiddenRouter.setPath(getRouterPath(hiddenMenu));
                    hiddenRouter.setComponent(hiddenMenu.getComponent());
                    hiddenRouter.setMeta(new MetaVo(hiddenMenu.getName(), hiddenMenu.getIcon()));

                    routers.add(hiddenRouter);
                }

            } else {
                if(!CollectionUtils.isEmpty(children)){
                    if(children.size() > 0) {
                        router.setAlwaysShow(true);
                    }
                    //递归
                    router.setChildren(buildRouter(children));
                }
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public String getRouterPath(SysMenu menu) {
        String routerPath = "/" + menu.getPath();
        if (menu.getParentId().intValue() != 0) {
            routerPath = menu.getPath();
        }
        return routerPath;
    }

    /**
     * 查询用户可以操作的按钮列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<String> findMenuPermsByUserId(Long userId) {
        List<SysMenu> sysMenuList = null;
        if (userId.equals(1L)) {
            //1.1 如果是则可以获取所有菜单列表
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysMenu::getStatus, 1);
            sysMenuList = baseMapper.selectList(queryWrapper);
        } else {
            //2. 不是管理员 根据userId查询可操作列表
            sysMenuList = baseMapper.findMenuListByUserId(userId);
        }

        //3. 从查询出来的数据中获取可以操作的按钮值的list集合，返回
        List<String> permsList = sysMenuList.stream()
                .filter(item -> item.getType() == 2)
                .map(item -> item.getPerms())
                .collect(Collectors.toList());

        return permsList;
    }
}
